# -*- coding: utf-8 -*-
class Bubble:
    def __init__(self, x, y, r, t, id, Gif_class, g2t):
        '''
        :param x: 坐标 网格坐标
        :param y:
        :param t: 开始时间s
        :param id: must
        '''
        self.id = id
        self.x = x
        self.y = y
        print('x,y', x, y)
        self.start_time = t  # 泡泡生成时间
        self.holding_duration = 4  # 爆炸等待时间
        self.anime_duration = 0.6 # 默认值
        self.real_explode = self.start_time + self.holding_duration  # 爆炸时间
        print('real', self.real_explode, self.start_time, self.holding_duration)
        self.has_exploded = False
        self.explode_range = []  # 爆炸十字范围
        self.radius = r  # 可以修改# 爆炸半径
        self.bubble_gif = None  # 动画
        self.grid2topleft = g2t
        self.explode_gifs = []  # 爆炸火焰
        self.explode_gif_dict = {}  # 爆炸火焰
        self.create_and_set_gif_and_start(Gif_class)
        
        self.all_ = []

 
        
        
    def get_effect_end_time(self):
        return self.real_explode+self.anime_duration
    
    def is_time_after_effect(self,cur):
        return cur > self.get_effect_end_time()
    def get_bubble_gif_topleft(self):
        '''
        泡泡绘制坐标
        :return:
        '''
        if self.grid2topleft:
            return self.grid2topleft(self.x, self.y)
        return self.x, self.y

    def new_bubble_gif(self, Gif_class):
        '''
        新建泡泡gif 弹弹弹
        :param Gif_class:
        :return:
        '''
        x, y = self.get_bubble_gif_topleft()
     
        if Gif_class:
            g = Gif_class(x, y, 'player_bubble3')
        else:
            return None
        return g

    def create_and_set_gif_and_start(self, Gif_class):
        '''
        创建泡泡动画 然后开始动画
        :param gif:
        :return:
        '''
        if Gif_class:
            gif = self.new_bubble_gif(Gif_class)
            gif.tick_time = 250
            gif.is_loop = True
            gif.start()

            self.bubble_gif = gif
        explode_range, hitted_brick = self.get_explode_range_and_brick([])
        if Gif_class:
            x, y = self.x, self.y
            for sx, sy in explode_range:
                direction = 'middle'
                if sx < x:
                    direction = 'left'
                if sx > x:
                    direction = 'right'
                if sy > y:
                    direction = 'down'
                if sy < y:
                    direction = 'up'
                x_, y_ = self.grid2topleft(sx, sy)
                g = Gif_class(x_, y_, 'flame_' + direction)
                g.tick_time = 125
                g.is_loop = False
                # g.start()
                self.explode_gif_dict[(sx, sy)] = g
                self.explode_gifs.append(g)

    def draw_bubble(self, draw_fun):
        # 画泡泡  （没爆炸
        if self.has_exploded: return
        g = self.bubble_gif
        img  = g.get_current_frame()
        draw_fun(g.get_current_frame(), g.topleft.x, g.topleft.y+ 40 - img.height)

    def draw_explode(self, draw_fun):
        # 画爆炸火焰
       

        for pos, g in self.explode_gif_dict.items():
            if pos not in self.explode_range:
                continue
            g.start()

            if g.is_end is False:
                draw_fun(g.get_current_frame(), g.topleft.x, g.topleft.y)

    def get_cross_section(self, pos, r, obstacle):
        '''
        get 十字 攻击范围 ， 原来用的函数
        :param pos:
        :param r:
        :param map_d:
        :return:
        '''

        x, y = pos
        brokens = []
        hitrange = []
        for dx, dy in [(0, 1), (1, 0), (0, -1), (-1, 0)]:
            for i in range(0, r):
                newx, newy = x + dx * i, y + dy * i
                p = (newx, newy)
                if p in obstacle:
                    brokens.append(p)
                    break
                else:
                    hitrange.append(p)
        hitrange.append(p)
        return list(set(hitrange)), brokens

    def get_explode_range_and_brick(self, obstacle):
        '''
        封装一层
        :param obstacle:
        :return:
        '''
        return self.get_cross_section((self.x, self.y), self.radius, obstacle)

    def get_position_to_bot_mapping(self, bots_, get_grid_idx):
        '''
        把bot 按网格 存成dict
        :param bots_:
        :param get_grid_idx:
        :return:
        '''
        # get_position2bot
        bot_dict = {}
        for bot in bots_:
            if get_grid_idx:
                if 'position' in bot:
                    grid = get_grid_idx(bot['position'].x, bot['position'].y)
                else:
                    grid = get_grid_idx(bot['pos'].x, bot['pos'].y)
                if grid not in bot_dict:
                    bot_dict[grid] = []
                bot_dict[grid].append(bot)
        return bot_dict

    def get_hitted_player(self, explode_range, grids2_player):
        '''
        被攻击的人物i
        :param explode_range:
        :param grids2_player:
        :return:
        '''
        hitted = []
        for grid, players in grids2_player.items():

            if grid in explode_range:
                hitted.extend(players)
        return hitted

    def get_hitted_bubbles(self, explode_range, bubbles, cur_time):
        hitted = []
        for b in bubbles:
            if b != self:
                if (b.x, b.y) in explode_range and b.is_holding(cur_time):
                    hitted.append(b)
        return hitted

    def is_holding(self, cur_time):
        # 是否未爆炸
       
        return cur_time < self.real_explode

    def wait_or_explode(self, bots_, bricks, cur_time, draw_fun, get_grid_idx):
        bubbles = []
        for b in bots_:
            bubbles.extend(b.get('bubbles_obj', []))

        if self.is_holding(cur_time):
           
            if draw_fun:
                self.draw_bubble(draw_fun)
            return [], []
        elif cur_time < self.real_explode + self.anime_duration:
          
            grid2player = self.get_position_to_bot_mapping(bots_, get_grid_idx)
            return self.explode_with_group(cur_time, draw_fun, grid2player, bubbles, bricks)
            # self.draw_explode(draw_fun)
        else:
            return [], []

    def explode(self, cur_time, grid2player, bubbles, bricks):
        # 爆炸
        if not self.has_exploded:
            if self.is_holding(cur_time) is False:
                
                self.explode_range, hitted_brick = self.get_explode_range_and_brick(bricks)
                hitted_players = self.get_hitted_player(self.explode_range, grid2player)
                hitted_bubbles = self.get_hitted_bubbles(self.explode_range, bubbles, cur_time)
                self.has_exploded = True
                self.real_explode = min(self.real_explode, cur_time)
                return hitted_players, hitted_brick, hitted_bubbles
        return [], [], []

    def explode_with_group(self, cur_time, draw_fun, grid2player, bubbles, bricks):
        if self.has_exploded:
            for b in [self] + self.all_:
               
                
                b.draw_explode(draw_fun)
            return [],[]
        all_ = []
        all_hitted_players = []
        explode_range, hitted_brick = self.get_explode_range_and_brick(bricks)
        all_hitted_brick = hitted_brick[:]
        self.explode_range = explode_range
        hitted_players = self.get_hitted_player(explode_range, grid2player)
        all_hitted_players.extend(hitted_players)
        hitted_bubbles = self.get_hitted_bubbles(explode_range, bubbles, cur_time)
        all_.extend(hitted_bubbles)
        while len(hitted_bubbles) > 0:
            current_bubble = hitted_bubbles.pop()
            explode_range, hitted_brick = current_bubble.get_explode_range_and_brick(bricks)
            hitted_players = current_bubble.get_hitted_player(explode_range, grid2player)
            current_bubble.explode_range = explode_range
            all_hitted_players.extend(hitted_players)
            hitted_bubbles = current_bubble.get_hitted_bubbles(explode_range, [b for b in bubbles if b not in all_],
                                                               cur_time)
            all_.extend(hitted_bubbles)
            all_hitted_brick.extend(hitted_brick)
            all_ = list(set(all_))
            # all_hitted_players = list(set(all_hitted_players))
        self.all_ = all_
        for b in [self] + all_:
            b.has_exploded = True
            print('draw exp', b.id)
            b.draw_explode(draw_fun)
        print('all_hitted_brick', all_hitted_brick)
        self.has_exploded = True
        return hitted_players, all_hitted_brick

class Jail:
    def __init__(self, x, y,  t, id, bot_dict):
        '''
        :param x: 坐标 网格坐标
        :param y:
        :param t: 开始时间s
        :param id: must
        '''
        self.id = id
        self.x = x
        self.y = y
        print('x,y', x, y)
        self.start_time = t  # 泡泡生成时间
        self.holding_duration = 4  # help max等待时间
        self.real_explode = self.start_time+self.holding_duration
        self.catch_player = bot_dict
        
    def is_holding(self, cur_time):
        # 是否未爆炸
        print(self.id, cur_time, self.real_explode)
        return cur_time < self.real_explode
    def wait_or_explode(self, cur_time):
        if self.is_holding(cur_time):
            print('is holding ')
            return False
        else:
            print('boom')
            u = {'state': 'alive' }
            self.catch_player.update(u)
            self.catch_player['player_state']['trap'] = False
            return True
        return False
            
            
# class PVector:
#     def __init__(self,x,y):
#         self.x = x
#         self.y = y

# import time
# t1=2
# b1 = Bubble(4, 3, 3, t1, 1, None, None)
# # b2 = Bubble(5, 3, 5, 4, 2, None, None)
# # {'position':PVector(100,200),'id': 2, 'bubbles_obj': [b2]}
# player ,all_hitted_brick =  b1.wait_or_explode([{'position':PVector(100,200),'id': 1, 'bubbles_obj': [b1]}],[(2,3),(3,3)], 6.1, None, None)
# print(all_hitted_brick)